/*
 * hilos.c
 *
 *  Created on: 28/11/2011
 *      Author: utn_so
 */

#include "hilos.h"

void *t_conexion_consola(void* v_cola)
{
	cola var_cola;
	var_cola = (cola) v_cola;
	uint32_t tamano_socket;
	uint8_t Socket, consola, longitud_path, n = 0;
	struct sockaddr_un local, remote;
	char mensaje[100];
	pid_t child_pid;

	if ((Socket = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
	{
		log_debug(archivoLogueo, "Consola", "No se creo el socket unix");
		pthread_exit(0);
	}
	local.sun_family = AF_UNIX;
	strcpy(local.sun_path, SOCK_PATH);
	unlink(local.sun_path);
	longitud_path = strlen(local.sun_path) + sizeof(local.sun_family);
	if (bind(Socket, (struct sockaddr *) &local, longitud_path) == -1)
	{
		log_debug(archivoLogueo, "Consola", "Error en el bind");
		pthread_exit(0);
	}

	if (listen(Socket, 1) == -1)
	{
		log_debug(archivoLogueo, "Consola", "Error en el listen");
		pthread_exit(0);
	}

	child_pid = fork();
	if (child_pid == 0)
	{
		/* Comienza a ejecutar el proceso hijo */
		char *argv[1];
		argv[0] = SOCK_PATH;
		execv(Consola, argv);

		/* Si continuó la ejecucion es porque fallo la llamada al exec */

		printf("No se ejecuto el execv\n");
		log_debug(archivoLogueo, "Consola", "Error al ejecutar la consola");
		pthread_exit(0);
	}
	tamano_socket = sizeof(remote);
	if ((consola = accept(Socket, (struct sockaddr *) &remote, &tamano_socket))
			== -1)
	{
		log_debug(archivoLogueo, "Consola", "Error en el accept");
		pthread_exit(0);
	}

	while (n >= 0)
	{
		memset(&mensaje[0], '\0', sizeof(char) * strlen(mensaje));
		n = recv(consola, mensaje, 100, 0);
		if (mensaje[0] == 'e')
			break;
		if (n <= 0)
		{
			if (n < 0)
			{
				log_debug(archivoLogueo, "Consola", "Error en el recv");
				pthread_exit(0);
			}
		}
		if (mensaje[0] == 'e')
			pthread_exit(0);

		if (!strcmp(configuracion.algoritmo, "NSTEP"))
			interpretar(consola, mensaje, mensaje, (t_list*) var_cola);
		if (!strcmp(configuracion.algoritmo, "SSTF"))
			interpretar(consola, mensaje, mensaje, (cola) var_cola);
	}
	close(consola);
	pthread_exit(0);
	return 0;
}

void *t_insertar(void* v_cola)
{
	t_sector sector;
	if (!strcmp(configuracion.modo, "CONNECT"))
	{
		conexion = conectarse_RAID(configuracion.ipRAID,
				configuracion.puertoRAID, configuracion.id_disco);
		if (conexion == -1)
		{
			perror("Error en la conexion");
			exit(1);
		}
		while (1)
		{
			sector = recibirSector(conexion);
			if (sector.type == -1)
			{
				close(conexion);
				continue;
			}
			sem_wait(&sem_cola);
			if (!strcmp(configuracion.algoritmo, "SSTF"))
			{
				PONER_EN_COLA_SSTF(sector, (cola) v_cola);
			}
			if (!strcmp(configuracion.algoritmo, "NSTEP"))
			{
				PONER_EN_COLA_NSTEP(sector, (t_list*) v_cola);
			}
			sem_post(&sem_cola);
			sem_post(&sem_sacar);
		}
	}
	if (!strcmp(configuracion.modo, "LISTEN"))
	{
		conexion = conectarse_FS(configuracion.ipPPD, configuracion.puertoPPD,
				configuracion.id_disco);
		fd_set fd_sMaestro;
		fd_set fd_sEsclavo;
		FD_ZERO(&fd_sMaestro);
		FD_SET(conexion, &fd_sMaestro);
		int32_t auxMaximoSocket;
		int32_t maximoSocket = auxMaximoSocket = conexion;
		int32_t n, i;
		while (1)
		{
			fd_sEsclavo = fd_sMaestro;
			n = select(maximoSocket + 1, &fd_sEsclavo, NULL, NULL, NULL);
			if (n == -1)
				perror("select"); //Error
			else
			{
				for (i = conexion; i <= maximoSocket; i++)
				{
					if (FD_ISSET(i,&fd_sEsclavo))
					{
						if (!strcmp(configuracion.modo, "LISTEN")
								&& (i == conexion))
						{
							int32_t client_sockfd = accept(conexion,
									(struct sockaddr *) NULL, NULL);
							printf("Conectado al File System\n");
							FD_SET(client_sockfd, &fd_sMaestro);
							if (client_sockfd > maximoSocket)
								auxMaximoSocket = client_sockfd;
						}
						else
						{
							sector = recibirSector(i);
							if (sector.type == -1)
							{
								printf("cerrando socket %d\n", i);
								close(i);
								continue;
							}
							if (sector.type == 0)
							{

								int resultado_handshake;
								printf("recibi bien ");
								resultado_handshake = handshakeFS_PPD(i,
										sector.type);
								if (resultado_handshake)
								{
									printf("error en el handshake");
									close(i);
								}
							}
							else
							{
								sem_wait(&sem_cola);
								if (!strcmp(configuracion.algoritmo, "SSTF"))
								{
									PONER_EN_COLA_SSTF(sector, (cola) v_cola);
								}
								if (!strcmp(configuracion.algoritmo, "NSTEP"))
								{
									PONER_EN_COLA_NSTEP(sector,
											(t_list*) v_cola);
								}
								sem_post(&sem_cola);
								sem_post(&sem_sacar);
							}
						}
					}
				}
				maximoSocket = auxMaximoSocket;
			}
		}
	}
	if (!conexion)
		exit(1);
	return 0;
}

void *t_sacar(void* v_cola)
{
	//char buffer_logueo[100];
	sectorSacado = (Sector) malloc(sizeof(t_sector));
	sectorSacado->direccion.cilindro = 0;
	sectorSacado->direccion.cabeza = 0;
	sectorSacado->direccion.sector = 0;
	sectorSacado->sock = 0;
	sectorSacado->type = 0;
	while (1)
	{
		//sleep(10);
		sem_wait(&sem_sacar);
		sem_wait(&sem_cola);
		if (!strcmp(configuracion.algoritmo, "SSTF"))
		{
			QUITAR_DE_COLA(sectorSacado, (cola) v_cola);
			//ver_cola(0,v_cola,NULL,1);
			//planificar(buffer_logueo,0,v_cola,0,0,1);
		}
		if (!strcmp(configuracion.algoritmo, "NSTEP"))
		{
			QUITAR_DE_COLA_NSTEP(sectorSacado, (t_list*) v_cola);
		}
		sem_post(&sem_cola);

		if (sectorSacado->type == Lectura)
		{
			leerSector(sectorSacado, DISCO, configuracion.tiempo_lectura);
			enviarSector(*sectorSacado);
		}
		if (sectorSacado->type == Escritura)
		{
			escribirSector(*sectorSacado, DISCO,
					configuracion.tiempo_escritura);
			enviarSector(*sectorSacado);
		}
		if (sectorSacado->type == Trace)
		{
			sem_post(&sem_trace);
			sem_wait(&fin_trace);
		}
		if (sectorSacado->type == Clean)
		{
			escribirSector(*sectorSacado, DISCO,
					configuracion.tiempo_escritura);
		}
	}
	free(sectorSacado);
	sectorSacado = NULL;
	return 0;
}
